1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//!This is the module to interact with the progmem memory
#![allow(unused_imports)]
/// Create a space for Progmem variable
/// ## Example
/// ```
/// use arduboy_rust::prelude::*;
/// //for text
/// progmem!(
///     static text: [u8; _] = *b"I'm a PROGMEM Text\0";
/// );
/// //for tone sequence
/// progmem!(
///     static tone: [u16; _] = [
///         NOTE_E4, 400, NOTE_D4, 200, NOTE_C4, 400, NOTE_D4, 200, NOTE_C4, 300, NOTE_REST,
///     ];
/// );
/// //for for bitmap
/// progmem!(
///     static image: [u8; _] = [8, 8, 0x81, 0x00, 0x12, 0x40, 0x04, 0x11, 0x00, 0x04];
/// );
///
/// // for a Vector
/// progmem!(
///     static mut walls: Vec<Player, 100> = Vec::new();
/// );
/// ```
#[macro_export]
macro_rules! progmem {
    (
        $( #[$attr:meta] )*
        $v:vis $id:ident $name:ident: [$ty:ty; _] = $value:expr;
        $($rest:tt)*
    ) => {
        $( #[$attr] )*
        #[link_section = ".progmem.data"]
        $v $id $name: [$ty; $value.len()] = $value;
        $crate::progmem!{
			$($rest)*
		}
    };
    (
        $( #[$attr:meta] )*
        $v:vis $id:ident mut $name:ident: [$ty:ty; _] = $value:expr;
        $($rest:tt)*
    ) => {
        $( #[$attr] )*
        #[link_section = ".progmem.data"]
        $v $id mut $name: [$ty; $value.len()] = $value;
        $crate::progmem!{
			$($rest)*
		}
    };
    (
        $( #[$attr:meta] )*
        $v:vis $id:ident $name:ident: $ty:ty = $value:expr;
        $($rest:tt)*
    ) => {
        $( #[$attr] )*
        #[link_section = ".progmem.data"]
        $v $id $name: $ty = $value;
        $crate::progmem!{
			$($rest)*
		}
    };
    (
        $( #[$attr:meta] )*
        $v:vis $id:ident mut $name:ident: $ty:ty = $value:expr;
        $($rest:tt)*
    ) => {
        $( #[$attr] )*
        #[link_section = ".progmem.data"]
        $v $id mut $name: $ty = $value;
        $crate::progmem!{
			$($rest)*
		}
    };
    () => ()
}

pub(super) use progmem;
///Create a `const` raw pointer to a sprite as u8, without creating an intermediate reference.
#[macro_export]
macro_rules! get_sprite_addr {
    ( $s:expr ) => {
        unsafe { addr_of!($s) as *const u8 }
    };
}
pub(super) use get_sprite_addr;

///Create a `const` raw pointer to a ardvoice tone as u8, without creating an intermediate reference.
#[macro_export]
macro_rules! get_ardvoice_tone_addr {
    ( $s:expr ) => {
        unsafe { addr_of!($s) as *const u8 }
    };
}
pub(super) use get_ardvoice_tone_addr;
///Create a `const` raw pointer to a tone sequenze as u16, without creating an intermediate reference.
#[macro_export]
macro_rules! get_tones_addr {
    ( $s:expr ) => {
        unsafe { addr_of!($s) as *const u16 }
    };
}
pub(super) use get_tones_addr;

///Create a `const` raw pointer to a \[u8;_] that saves text, without creating an intermediate reference.
#[macro_export]
macro_rules! get_string_addr {
    ( $s:expr ) => {
        Pstring {
            pointer: unsafe { addr_of!($s) as *const i8 },
        }
    };
}
pub(super) use get_string_addr;
///This is the way to go if you want print some random text
///
/// This doesn't waste the 2kb ram it saves to progmem (28kb)
/// This automatically saves the given text to the Progmem.
/// ## Example
/// ```
/// use arduboy_rust::prelude::*;
/// #[allow(non_upper_case_globals)]
/// const arduboy: Arduboy2 = Arduboy2::new();
/// arduboy.print(f!(b"Random text to print\0"))
/// ```
#[macro_export]
macro_rules! f {
    ($string_literal:literal) => {{
        progmem!(
            static local: [u8; _] = *$string_literal;
        );

        get_string_addr!(local)
    }};
}
pub(super) use f;

/// This struct is important for the Progmem functionality.
///
/// Typically you will never use this by your self.
/// It will be used by the get_string_addr macro in combination with a print command.
#[derive(Copy, Clone)]
pub struct Pstring {
    pub pointer: *const i8,
}